use crate::error::BufferError;
use crate::error::ProtoError;

use protobuf::Message;

use std::{collections::VecDeque, io::Bytes};

/// 因为protobuf不是定长的协议，因此ProtoBuffer采用以下形式
///
/// [header1](4个字节，转成u32表示内容对应字节数组的长度)、[content1](vec<u8>)、
///
/// [header2](4个字节，同理)、[content2](vec<u8>)...
///
pub struct ProtoBuffer {
    buffer: Vec<u8>,
}

impl ProtoBuffer {
    pub fn from_slice(slice: &[u8]) -> Self {
        Self {
            buffer: slice.to_vec(),
        }
    }

    pub fn from_vec(vec: Vec<u8>) -> Self {
        Self { buffer: vec }
    }

    pub fn new() -> Self {
        Self { buffer: Vec::new() }
    }

    pub fn clear(&mut self) {
        self.buffer.clear();
    }

    pub fn and_write<M>(&mut self, message: &M) -> Result<(), ProtoError>
    where
        M: Message,
    {
        let bytes = message.write_to_bytes()?;
        log::trace!("header:{}", bytes.len());
        let header = (bytes.len() as u32).to_le_bytes();
        log::trace!("and write,header:{:?}", header);
        log::trace!("bytes:{:?}", bytes.as_slice());

        self.buffer.extend_from_slice(header.as_slice());

        self.buffer.extend_from_slice(bytes.as_slice());

        log::trace!("and write,buffer:{:?}", self.buffer);
        Ok(())
    }

    pub fn and_read<M>(&mut self) -> Result<M, ProtoError>
    where
        M: Message,
    {
        if self.buffer.len() <= 4 {
            return Err(BufferError().into());
        }

        let mut retain = self.buffer.split_off(4);

        log::trace!("header_bytes:{:?}", self.buffer);

        // 使用 unsafe 将 Vec<u8> 转换为 u32（小端序）
        let header_le = unsafe {
            // assert_eq!(self.buffer.len(), std::mem::size_of::<u32>());
            *(self.buffer.as_ptr() as *const u32)
        };

        log::trace!("header_le:{:?}", header_le);

        let s = &self.buffer[0..4];

        log::trace!("test:{:?}", &retain[0..((0 + header_le) - 1) as usize]);

        log::trace!("body:{:?}", &retain[0..(0 + header_le) as usize]);

        let decoder: M = M::parse_from_bytes(&retain[0..(header_le) as usize])?;

        self.buffer = retain.split_off(header_le as usize);
        log::trace!("after split off:{:?}", self.buffer);

        Ok(decoder)
    }

    pub fn try_pop_all(self) -> Option<Vec<u8>> {
        if self.buffer.is_empty() {
            return None;
        }
        Some(self.buffer)
    }
}

#[cfg(test)]
mod tests {
    use protobuf::Message;

    use crate::{buf::ProtoBuffer, protobuf::example::GetRequest};
    #[test]
    fn test_protobuf_rs() {
        let mut req0 = GetRequest::new();
        req0.name = "name0".to_string();
        req0.age = 1;
        req0.features = vec!["feature 0".to_string()];

        let vec = req0.write_to_bytes().expect("msg");
        let mut buffer = ProtoBuffer::from_vec(vec);

        let mut req1 = GetRequest::new();
        req1.name = "name1".to_string();
        req1.age = 1;
        req1.features = vec!["feature 1".to_string()];

        let bytes = req1.write_to_bytes().expect("msg");
        buffer.and_write(&req1);

        let mut req2 = GetRequest::new();
        req2.name = "name2".to_string();
        req2.age = 2;
        req2.features = vec!["feature 2".to_string()];

        buffer.and_write(&req2);

        let req11 = buffer.and_read::<GetRequest>().expect("and read err1");
        println!("req11:{}", req11);

        let req22 = buffer.and_read::<GetRequest>().expect("and read err2");
        println!("req22:{}", req22);
    }
}
